home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / program / swagg_m.zip / MISC.SWG / 0103_DBase III Routines.pas < prev    next >
Pascal/Delphi Source File  |  1994-08-24  |  37KB  |  1,410 lines

  1. {---------------------------------------------------------}
  2. {  Unit    : Dbase III Access Routines                    }
  3. {  Auteur  : Ir. G.W. van der Vegt                        }
  4. {            Hondsbroek 57                                }
  5. {            6121 XB Born                                 }
  6. {---------------------------------------------------------}
  7. {  Datum .tijd  Revisie                                   }
  8. {  910701.2130  Creatie.                                  }
  9. {  910702.1000  Minor Errors Corrected                    }
  10. {               Replace, Append & Pack Added              }
  11. {  910706.2400  dbrec on the Heap (recsize max 64kB-16)   }
  12. {               Uppercase Conversion in Bd3_fileno        }
  13. {               Optional Halt on (fatal) Errors           }
  14. {  910710.1500  Memo Field Support                        }
  15. {  910715.2330  Field2num bug fixed (leading sp. removed) }
  16. {  910960.1130  Fieldno Out of range detection            }
  17. {  920116.1000  Two minor bugs fixed                      }
  18. {  920124.2200  Header updated when file is closed,       }
  19. {               Db3_Seekbof & Db3_Seekeof added           }
  20. {               Db3_Findfirst & Db3_Findnext implemented  }
  21. {               for wildcard search of records            }
  22. {               Db3_soudex & Db3_field2soundex for Soundex}
  23. {               code (sound alike) operations             }
  24. {               Db3_firstsoudex & Db3_nextsoundex for     }
  25. {               soundex search on a field                 }
  26. {  920127.1300  Dbase Slack Filespace Detection &         }
  27. {               Correction                                }
  28. {  920129.2115  Trailing spaces remover in Db3_field2str  }
  29. {               Seek after truncate in Db3_open           }
  30. {  920130.2145  Slack filespace bug removed               }
  31. {               Db3_sort implemented (based on shakersort)}
  32. {               Bug in Db3_date2field removed             }
  33. {  920716.2130  Empty file pack fixed in Db3_pack         }
  34. {  920928.2200  Obscure bug in Db3_fieldname. Fieldnames  }
  35. {               seem to be are ASCIZ in stead of fixed    }
  36. {               length strings.                           }
  37. {  930927.2000  Freemem bug in db3_findnext corrected.    }
  38. {---------------------------------------------------------}
  39. {  To Do        Full Documentation                        }
  40. {               Write Memo Support                        }
  41. {               Extend Db3_pack with MemoFile Packing     }
  42. {               Sort *.DBF in place                       }
  43. {               Insert record in *.DBF file               }
  44. {               Date format not always yy-mm-dd           }
  45. {---------------------------------------------------------}
  46.  
  47. UNIT Db3_01;
  48.  
  49. INTERFACE
  50.  
  51. USES
  52.   DOS;
  53.  
  54. {---------------------------------------------------------}
  55. {----Error Handling : Returns First Error Which Occured   }
  56. {---------------------------------------------------------}
  57.  
  58. VAR
  59.   db3_ernr     : INTEGER;                    {----DB3 Module Error Code}
  60.   db3_fatal    : BOOLEAN;                    {----IF True
  61.                                                     THEN Halt(db3_ernr)
  62.                                                   on an error}
  63.  
  64.   db3_memotext : TEXT;                       {----Memo File}
  65.  
  66. {---------------------------------------------------------}
  67.  
  68. FUNCTION  Db3_ermsg(nr : INTEGER) : STRING;
  69.  
  70. {---------------------------------------------------------}
  71. {----Initialize/Exit : Must both be Called for every file }
  72. {---------------------------------------------------------}
  73.  
  74. PROCEDURE Db3_open(fn : STRING);             {----Opens fn.DBF file &
  75.                                                   Inits Internals}
  76. PROCEDURE Db3_close;                         {----Closes fn.DBF file}
  77.  
  78. {---------------------------------------------------------}
  79. {----Header Function : Get .DBF header info               }
  80. {---------------------------------------------------------}
  81.  
  82. FUNCTION  Db3_memo : BOOLEAN;
  83.  
  84. FUNCTION  Db3_update : STRING;
  85.  
  86. FUNCTION  Db3_norecs : LONGINT;
  87.  
  88. FUNCTION  Db3_nofields : INTEGER;
  89.  
  90. FUNCTION  Db3_reclen : INTEGER;
  91.  
  92. {---------------------------------------------------------}
  93. {----File I/O : Dbase III Alike (pos etc. in records)     }
  94. {---------------------------------------------------------}
  95.  
  96. PROCEDURE Db3_seek(pos : LONGINT);
  97.  
  98. FUNCTION  Db3_filesize : LONGINT;
  99.  
  100. FUNCTION  Db3_filepos : LONGINT;
  101.  
  102. PROCEDURE Db3_readnext;
  103.  
  104. PROCEDURE Db3_read(pos : LONGINT);
  105.  
  106. PROCEDURE Db3_seekeof;
  107.  
  108. PROCEDURE Db3_seekbof;
  109.  
  110. FUNCTION  Db3_eof : BOOLEAN;
  111.  
  112. FUNCTION  Db3_bof : BOOLEAN;
  113.  
  114. PROCEDURE Db3_replace(no : LONGINT);         {----First Read record &
  115.                                                   Fill all fields}
  116. PROCEDURE Db3_append;                        {----First Fill all Fields}
  117.  
  118. PROCEDURE Db3_delete(no : LONGINT);
  119.  
  120. PROCEDURE Db3_undelete(no : LONGINT);
  121.  
  122. PROCEDURE Db3_pack;                          {----Packs File IN-PLACE}
  123.  
  124. PROCEDURE Db3_blankrec;
  125.  
  126. {---------------------------------------------------------}
  127. {----Field Operations : no is .DBF field number           }
  128. {---------------------------------------------------------}
  129.  
  130. FUNCTION  Db3_fieldname(no : INTEGER) : STRING;
  131.  
  132. FUNCTION  Db3_fieldlen(no : INTEGER) : INTEGER;
  133.  
  134. FUNCTION  Db3_fielddec(no : INTEGER) : INTEGER;
  135.  
  136. FUNCTION  Db3_fieldno(name : STRING) : INTEGER; {----Searches Fieldnumber for
  137.                                                      Uppercase fieldname}
  138. FUNCTION  Db3_fieldtype(no : INTEGER) : CHAR;
  139.  
  140. FUNCTION  Db3_deleted : BOOLEAN;
  141.  
  142. {---------------------------------------------------------}
  143. {----Field Conversions : date format 'dd-mm-19yy'         }
  144. {---------------------------------------------------------}
  145.  
  146. FUNCTION  Db3_field2str(no :INTEGER) : STRING;
  147.  
  148. FUNCTION  Db3_field2char(no :INTEGER) : CHAR;
  149.  
  150. FUNCTION  Db3_field2logic(no : INTEGER) : BOOLEAN;
  151.  
  152. FUNCTION  Db3_field2num(no : INTEGER) : REAL;
  153.  
  154. FUNCTION  Db3_field2date(no :INTEGER) : STRING;
  155.  
  156. PROCEDURE Db3_field2memo(no : INTEGER);
  157.  
  158. FUNCTION  Db3_field2soundex(no : INTEGER) : STRING;
  159.  
  160. PROCEDURE Db3_str2field(no :INTEGER;s : STRING);
  161.  
  162. PROCEDURE Db3_char2field(no :INTEGER;s : CHAR);
  163.  
  164. PROCEDURE Db3_logic2field(no : INTEGER;l : BOOLEAN);
  165.  
  166. PROCEDURE Db3_num2field(no : INTEGER;n : REAL);
  167.  
  168. PROCEDURE Db3_date2field(no :INTEGER;d : STRING);
  169.  
  170. {---------------------------------------------------------}
  171. {----Database Search, spaces are used as wildcards.       }
  172. {    Db3_blankrec can be used for creating a wildcard     }
  173. {    record. Then if Findfirst is true the use Findnext   }
  174. {    until Findnext becomes false. After each succesfull  }
  175. {    call the internal readbuffer will contain the        }
  176. {    matching record. Use casesense=true for a case       }
  177. {    sensitive search.                                    }
  178. {---------------------------------------------------------}
  179.  
  180. FUNCTION Db3_findfirst(cs : BOOLEAN) : BOOLEAN;
  181.  
  182. FUNCTION Db3_findnext(cs : BOOLEAN) : BOOLEAN;
  183.  
  184. {---------------------------------------------------------}
  185. {----Soundex Code Function (sound alike)                  }
  186. {---------------------------------------------------------}
  187.  
  188. FUNCTION  Db3_soundex(name : STRING) : STRING;
  189.  
  190. FUNCTION  Db3_firstsoundex(no : INTEGER; s : STRING) : BOOLEAN;
  191.  
  192. FUNCTION  Db3_nextsoundex(no : INTEGER; s : STRING) : BOOLEAN;
  193.  
  194. {---------------------------------------------------------}
  195. {----Shaker Sort Almost Sorted *.DBF Files                }
  196. {---------------------------------------------------------}
  197.  
  198. PROCEDURE Db3_sort(no : INTEGER);
  199.  
  200. IMPLEMENTATION
  201.  
  202. {---------------------------------------------------------}
  203. {----Error Handling                                       }
  204. {---------------------------------------------------------}
  205.  
  206. PROCEDURE Seternr(e : INTEGER);
  207.  
  208. BEGIN
  209.   IF (db3_ernr=0) THEN db3_ernr:=e;
  210.   IF db3_fatal
  211.     THEN
  212.       BEGIN
  213.         Writeln;
  214.         Writeln('Db3_01 [Error : ',db3_ernr:0,' = '+Db3_ermsg(db3_ernr)+']');
  215.         Writeln;
  216.         IF (db3_ernr<>1) THEN Db3_close;
  217.         Halt(e);
  218.       END;
  219. END; {of Seternr}
  220.  
  221. {---------------------------------------------------------}
  222.  
  223. FUNCTION  Db3_ermsg(nr : INTEGER) : STRING;
  224.  
  225. BEGIN
  226.   CASE nr OF
  227.     0 : Db3_ermsg:='No Error';
  228.     1 : Db3_ermsg:='Error Opening File';
  229.     2 : Db3_ermsg:='Seek Past EOF';
  230.     3 : Db3_ermsg:='Seek Before BOF';
  231.     4 : Db3_ermsg:='Read Past EOF';
  232.     5 : Db3_ermsg:='Invalid Numeric Field';
  233.     6 : Db3_ermsg:='Field Name NOT Found';
  234.     7 : Db3_ermsg:='Invalid Header';
  235.     8 : Db3_ermsg:='Incorrect Filesize';
  236.     9 : Db3_ermsg:='Records to Large';
  237.    10 : Db3_ermsg:='To many Fields';
  238.    11 : Db3_ermsg:='Invalid Date Format';
  239.    12 : Db3_ermsg:='Cannot Format Real';
  240.    13 : Db3_ermsg:='Record was already deleted';
  241.    14 : Db3_ermsg:='Record was not deleted';
  242.    15 : Db3_ermsg:='NOT a Dbase III File';
  243.    16 : Db3_ermsg:='Field Number NOT Found';
  244.    17 : Db3_ermsg:='No Memofields in this file';
  245.    18 : Db3_ermsg:='All matching records already found';
  246.    19 : Db3_ermsg:='No *.DBF file open';
  247.    20 : Db3_ermsg:='*.DBF already file open';
  248.    99 : Db3_ermsg:='NOT Yet Implemented';
  249.   ELSE Db3_ermsg:='Unkown Error';
  250.   END;
  251.  
  252.   db3_ernr:=0;
  253. END; {of Db3_ermsg}
  254.  
  255. {---------------------------------------------------------}
  256. {----Types/Vars & Constants                               }
  257. {---------------------------------------------------------}
  258.  
  259. TYPE
  260.   dbheader = RECORD
  261.                dbvers : BYTE;
  262.                dbupdy,
  263.                dbupdm,
  264.                dbupdd : BYTE;
  265.                dbnorec: LONGINT;
  266.                dbheadl,
  267.                dbrecl : INTEGER;
  268.                dbres  : ARRAY[1..20] OF BYTE;
  269.              END;
  270.  
  271.   dbfield  = RECORD                          {----Definition of Field Header}
  272.                dbname : ARRAY[1..11] OF CHAR;
  273.                dbtype : CHAR;
  274.                dbadr  : LONGINT;
  275.                dblen,
  276.                dbdec  : BYTE;
  277.                dbres  : ARRAY[1..14] OF CHAR;
  278.              END;
  279.  
  280.   fptr     = RECORD                          {----Definition of Readbuf Index}
  281.                fppos   : WORD;
  282.                fplen   : BYTE;
  283.              END;
  284.  
  285. CONST
  286.   maxfield =    60;                          {----Max number of Fields}
  287.   maxsize  = 65000;                          {----Maximum Record Size}
  288.  
  289. TYPE
  290.   rectyp   = ARRAY[0..maxsize] OF CHAR;      {----Record Readbuffer Type}
  291.  
  292. VAR
  293.   f        : file;                           {----.DBF File}
  294.  
  295.   header   : dbheader;                       {----Space for Header}
  296.   nofields : INTEGER;                        {----Number of Fields}
  297.  
  298.   fields   : ARRAY[1..maxfield] OF dbfield;  {----Field Definitions}
  299.   fieldptr : ARRAY[1..maxfield] OF fptr;     {----Index into Readbuffer}
  300.   recstart : LONGINT;                        {----Start of Record Area}
  301.  
  302.   dbrec    : ^rectyp;                        {----Record Buffer}
  303.   reclen   : WORD;                           {----Record Length}
  304.  
  305.   memo     : FILE;                           {----Memo File}
  306.   memopos  : LONGINT;                        {----Location of Memo Record}
  307.   memobuf  : ARRAY[1..512] OF CHAR;          {----Memo Text File buffer}
  308.  
  309.   dbsearch : ^rectyp;                        {----Search Record Buffer}
  310.  
  311. {---------------------------------------------------------}
  312. {----Initialize                                           }
  313. {---------------------------------------------------------}
  314.  
  315. PROCEDURE Db3_open(fn : STRING);
  316.  
  317. VAR
  318.   i   : INTEGER;
  319.   j   : WORD;
  320.   ch  : CHAR;
  321.  
  322. BEGIN
  323.   IF (dbrec<>NIL)
  324.     THEN Seternr(20)
  325.     ELSE
  326.       BEGIN
  327.         Assign(f,fn+'.DBF');
  328.         {$I-} Reset(f,1); {$I+}
  329.         IF (Ioresult<>0)
  330.           THEN Seternr(1)
  331.           ELSE
  332.             BEGIN
  333.             {----Dump Header}
  334.               Blockread(f,header,32);
  335.  
  336.               Getmem(dbrec,header.dbrecl+1);
  337.  
  338.             {---Scan for Fieldnames & Recordlength}
  339.               reclen  :=1;
  340.               nofields:=0;
  341.               Blockread(f,ch,1);
  342.               WHILE (nofields<maxfield) AND (ch<>#13) DO
  343.                 BEGIN
  344.                   Inc(nofields);
  345.                   WITH fields[nofields] DO
  346.                     BEGIN
  347.                       dbname[1]:=ch;
  348.                       Blockread(f,dbname[2],Sizeof(dbfield)-1);
  349.                       Inc(reclen,dblen);
  350.                       Blockread(f,ch,1);
  351.                     END;
  352.                 END;
  353.  
  354.               IF (ch<>#13) THEN Seternr(10);
  355.  
  356.             {----Zapped file contains only a EOF}
  357.               recstart:=Filepos(f);
  358.  
  359.             {----Set fieldptr}
  360.               j:=1;
  361.               FOR i:=1 TO nofields DO
  362.                 WITH fieldptr[i],fields[i] DO
  363.                   BEGIN
  364.                     fplen:=dblen;
  365.                     fppos:=j;
  366.                     Inc(j,dblen);
  367.                   END;
  368.  
  369.             {----Header Integrity Checks}
  370.               IF NOT(header.dbvers IN [$03,$83]) THEN Seternr(15);
  371.  
  372.               IF ((header.dbheadl DIV 32)-1<>nofields) OR
  373.                   (header.dbrecl<>reclen)
  374.                 THEN Seternr(7);
  375.  
  376.             {----File Size Check}
  377.               IF (header.dbnorec*reclen<>(Filesize(f)-recstart-1))
  378.                 THEN
  379.                   BEGIN
  380.                   {----Truncate DBASE Slack Filespace}
  381.                   { Writeln('Truncating'); }
  382.                     Db3_Seek(header.dbnorec+1);
  383.                     {$I-} Seek(f,Filepos(f)+1); {$I+}
  384.                     IF (IOresult=0)
  385.                       THEN Truncate(f)
  386.                       ELSE Seternr(8);
  387.                   END;
  388.  
  389.               IF (reclen>Sizeof(rectyp)) THEN Seternr(9);
  390.  
  391.               IF Db3_memo
  392.                 THEN
  393.                   BEGIN
  394.                     Assign(memo,fn+'.DBT');
  395.                     {$I-} Reset(memo,1); {$I+}
  396.                     IF (IOresult<>0) THEN Seternr(17);
  397.                   END;
  398.  
  399.               IF (db3_ernr<>0) THEN Freemem(dbrec,header.dbrecl+1);
  400.             END;
  401.  
  402.         IF (db3_ernr<>0)
  403.           THEN dbrec:=NIL
  404.           ELSE Db3_Seekbof
  405.  
  406.       END;
  407. END; {of Db3_open}
  408.  
  409. {---------------------------------------------------------}
  410.  
  411. PROCEDURE Db3_close;
  412.  
  413. VAR
  414.   y,m,d,dow : WORD;
  415.  
  416. BEGIN
  417.   IF (dbrec<>NIL)
  418.     THEN
  419.       BEGIN
  420.       {----Update *.DBF File Header}
  421.         Getdate(y,m,d,dow);
  422.         WITH header DO
  423.           BEGIN
  424.             dbupdy :=y MOD 100;
  425.             dbupdm :=m;
  426.             dbupdd :=d;
  427.             dbnorec:=Db3_filesize;
  428.           END;
  429.         Reset(f,1);
  430.         Blockwrite(f,header,32);
  431.         Close(f);
  432.  
  433.       {----Cleanup Memory}
  434.         Freemem(dbrec,header.dbrecl+1);
  435.         IF dbsearch<>NIL THEN Freemem(dbsearch,header.dbrecl+1);
  436.  
  437.         dbrec    :=NIL;
  438.         dbsearch :=NIL;
  439.       END
  440.     ELSE Seternr(19);
  441. END; {of DB3_close}
  442.  
  443. {---------------------------------------------------------}
  444. {----Header Operations                                    }
  445. {---------------------------------------------------------}
  446.  
  447. FUNCTION  Db3_memo : BOOLEAN;
  448.  
  449. BEGIN
  450.   Db3_memo:=header.dbvers=$83;
  451. END; {of Db3_memo}
  452.  
  453. {---------------------------------------------------------}
  454.  
  455. FUNCTION  Db3_update : STRING;
  456.  
  457. VAR
  458.   s : STRING;
  459.  
  460. BEGIN
  461.   s:='dd-mm-19yy';
  462.   s[ 1]:=Chr(Ord('0')+header.dbupdd DIV 10);
  463.   s[ 2]:=Chr(Ord('0')+header.dbupdd MOD 10);
  464.   s[ 4]:=Chr(Ord('0')+header.dbupdm DIV 10);
  465.   s[ 5]:=Chr(Ord('0')+header.dbupdm MOD 10);
  466.   s[ 9]:=Chr(Ord('0')+header.dbupdy DIV 10);
  467.   s[10]:=Chr(Ord('0')+header.dbupdy MOD 10);
  468.  
  469.   Db3_update:=s;
  470. END; {of Db3_update}
  471.  
  472. {---------------------------------------------------------}
  473.  
  474. FUNCTION  Db3_norecs : LONGINT;
  475.  
  476. BEGIN
  477.   Db3_norecs:=header.dbnorec;
  478. END; {of Db3_norecs}
  479.  
  480. {---------------------------------------------------------}
  481.  
  482. FUNCTION  Db3_nofields : INTEGER;
  483.  
  484. BEGIN
  485.   Db3_nofields:=nofields;
  486. END; {of Db3_nofields}
  487.  
  488. {---------------------------------------------------------}
  489.  
  490. FUNCTION  Db3_reclen : INTEGER;
  491.  
  492. BEGIN
  493.   Db3_reclen:=reclen;
  494. END; {of Db3_reclen}
  495.  
  496. {---------------------------------------------------------}
  497. {----File I/O                                             }
  498. {---------------------------------------------------------}
  499.  
  500. PROCEDURE Db3_seek(pos : LONGINT);
  501.  
  502. BEGIN
  503.   {$I-} Seek(f,recstart+(pos-1)*reclen); {$I+}
  504.   IF (Ioresult<>0) OR (pos<1) OR (pos>Db3_filesize+1)
  505.     THEN
  506.       BEGIN
  507.         IF (pos>0)
  508.           THEN Seternr(2)
  509.           ELSE Seternr(3);
  510.       END;
  511. END; {of Db3_seek}
  512.  
  513. {---------------------------------------------------------}
  514.  
  515. FUNCTION  Db3_filesize : LONGINT;
  516.  
  517. BEGIN
  518.   Db3_filesize:=(Filesize(f)-recstart) DIV reclen;
  519. END; {of Db3_filesize}
  520.  
  521. {---------------------------------------------------------}
  522.  
  523. FUNCTION  Db3_filepos : LONGINT;
  524.  
  525. BEGIN
  526.   Db3_filepos:=((Filepos(f)-recstart) DIV reclen)+1;
  527. END; {of Db3_filepos}
  528.  
  529. {---------------------------------------------------------}
  530.  
  531. PROCEDURE Db3_readnext;
  532.  
  533. BEGIN
  534.   IF EOF(f) OR Db3_Eof
  535.     THEN Seternr(4)
  536.     ELSE Blockread(f,dbrec^,reclen);
  537. END; {of Db3_readnext}
  538.  
  539. {---------------------------------------------------------}
  540.  
  541. PROCEDURE Db3_read(pos : LONGINT);
  542.  
  543. BEGIN
  544.   Db3_seek(pos);
  545.   Db3_readnext;
  546. END; {of Db3_read}
  547.  
  548. {---------------------------------------------------------}
  549.  
  550. PROCEDURE Db3_seekeof;
  551.  
  552. BEGIN
  553.   Db3_Seek(Db3_filesize+1);
  554. END; {of Db3_seekeof}
  555.  
  556. {---------------------------------------------------------}
  557.  
  558. PROCEDURE Db3_seekbof;
  559.  
  560. BEGIN
  561.   Seek(f,recstart);
  562. END; {of Db3_seekeof}
  563.  
  564. {---------------------------------------------------------}
  565.  
  566. FUNCTION  Db3_eof : BOOLEAN;
  567.  
  568. BEGIN
  569.   Db3_eof:=(Filepos(f)>=Filesize(f)-1);
  570. END; {of Db3_eof}
  571.  
  572. {---------------------------------------------------------}
  573.  
  574. FUNCTION  Db3_bof : BOOLEAN;
  575.  
  576. BEGIN
  577.   Db3_bof:=Filepos(f)=recstart;
  578. END; {of Db3_bof}
  579.  
  580. {---------------------------------------------------------}
  581.  
  582. PROCEDURE Db3_replace(no : LONGINT);
  583.  
  584. BEGIN
  585.   Db3_seek(no);
  586.   IF (db3_ernr=0) THEN Blockwrite(f,dbrec^[0],reclen)
  587. END; {of Db3_append}
  588.  
  589. {---------------------------------------------------------}
  590.  
  591. PROCEDURE Db3_append;
  592.  
  593. VAR
  594.   ch : CHAR;
  595.  
  596. BEGIN
  597.   Db3_seek(Db3_filesize+1);
  598.   Blockwrite(f,dbrec^[0],reclen);
  599.   ch:=^Z;
  600.   Blockwrite(f,ch,1);
  601.   Db3_seek(Db3_filesize+1);
  602. END; {of Db3_append}
  603.  
  604. {---------------------------------------------------------}
  605.  
  606. PROCEDURE Db3_delete(no : LONGINT);
  607.  
  608. BEGIN
  609.   Db3_read(no);
  610.   IF dbrec^[0]='*'
  611.     THEN Seternr(13)
  612.     ELSE dbrec^[0]:='*';
  613.   Db3_replace(no)
  614. END; {of Db3_delete}
  615.  
  616. {---------------------------------------------------------}
  617.  
  618. PROCEDURE Db3_undelete(no : LONGINT);
  619.  
  620. BEGIN
  621.   Db3_read(no);
  622.   IF dbrec^[0]=' '
  623.     THEN Seternr(14)
  624.     ELSE dbrec^[0]:=' ';
  625.   Db3_replace(no)
  626. END; {of Db3_undelete}
  627.  
  628. {---------------------------------------------------------}
  629.  
  630. PROCEDURE Db3_pack;
  631.  
  632. VAR
  633.   i,j : LONGINT;
  634.   ch  : CHAR;
  635.  
  636. BEGIN
  637.   j:=0;
  638.   FOR i:=1 TO Db3_filesize DO
  639.     BEGIN
  640.       Db3_read(i);
  641.       IF NOT(Db3_deleted)
  642.         THEN
  643.           BEGIN
  644.             Inc(j);
  645.             Db3_replace(j)
  646.           END
  647.     END;
  648.  
  649. {----New EOF Marker}
  650.   IF (j=0)
  651.     THEN db3_SeekBof
  652.     ELSE Db3_read(j);
  653.   ch:=^Z;
  654.   Blockwrite(f,ch,1);
  655.   Truncate(f);
  656.  
  657.   Db3_seek(1);
  658. END; {of Db3_pack}
  659.  
  660. {---------------------------------------------------------}
  661.  
  662. PROCEDURE Db3_blankrec;
  663.  
  664. VAR
  665.   i : INTEGER;
  666.  
  667. BEGIN
  668.   FOR i:=0 TO reclen-1 DO dbrec^[i]:=#32;
  669. END; {of Db3_blankrec}
  670.  
  671. {---------------------------------------------------------}
  672. {----Field Operations                                     }
  673. {---------------------------------------------------------}
  674.  
  675. FUNCTION  Db3_fieldname(no : INTEGER) : STRING;
  676.  
  677. VAR
  678.   s : STRING;
  679.   i : WORD;
  680.  
  681. BEGIN
  682.   s:='';
  683.   i:=1;
  684.   IF no IN [1..nofields]
  685.     THEN
  686.       BEGIN
  687.         WITH fields[no] DO
  688.           WHILE (i<=Sizeof(dbname)) AND (dbname[i]<>#0) DO
  689.             BEGIN
  690.               s:=s+dbname[i];
  691.               Inc(i);
  692.             END;
  693.       END
  694.     ELSE Seternr(16);
  695.   Db3_fieldname:=s;
  696. END; {of Db3_fieldname}
  697.  
  698. {---------------------------------------------------------}
  699.  
  700. FUNCTION  Db3_fieldlen(no : INTEGER) : INTEGER;
  701.  
  702. BEGIN
  703.   Db3_fieldlen:=0;
  704.   IF no IN [1..nofields]
  705.     THEN Db3_fieldlen:=fields[no].dblen
  706.     ELSE Seternr(16);
  707. END; {of Db3_fieldlen}
  708.  
  709. {---------------------------------------------------------}
  710.  
  711. FUNCTION  Db3_fielddec(no : INTEGER) : INTEGER;
  712.  
  713. BEGIN
  714.   Db3_fielddec:=0;
  715.   IF no IN [1..nofields]
  716.     THEN Db3_fielddec:=fields[no].dbdec
  717.     ELSE Seternr(16)
  718. END; {of Db3_fielddec}
  719.  
  720. {---------------------------------------------------------}
  721.  
  722. FUNCTION  Db3_fieldno(name : STRING) : INTEGER;
  723.  
  724. VAR
  725.   i,j : INTEGER;
  726.   s   : STRING;
  727.  
  728. BEGIN
  729.   Db3_fieldno:=0;
  730.  
  731.   s:=name;
  732.   FOR i:=1 TO Length(s) DO s[i]:=Upcase(s[i]);
  733.  
  734.   i:=1;
  735.   WHILE (i<=nofields) AND (s<>Db3_fieldname(i)) DO
  736.     Inc(i);
  737.  
  738.   IF (i>nofields)
  739.     THEN Seternr(6)
  740.     ELSE Db3_fieldno:=i;
  741. END; {of Db3_fieldno}
  742.  
  743. {---------------------------------------------------------}
  744.  
  745. FUNCTION  Db3_fieldtype(no : INTEGER) : CHAR;
  746.  
  747. BEGIN
  748.   Db3_fieldtype:=#00;
  749.   IF no IN [1..nofields]
  750.     THEN Db3_fieldtype:=fields[no].dbtype
  751.     ELSE Seternr(16);
  752. END; {of Db3_fieldtype}
  753.  
  754. {---------------------------------------------------------}
  755.  
  756. FUNCTION  Db3_deleted : BOOLEAN;
  757.  
  758. BEGIN
  759.   Db3_deleted:=dbrec^[0]<>#32;
  760. END; {of Db3_deleted}
  761.  
  762. {---------------------------------------------------------}
  763. {----Field Conversions                                    }
  764. {---------------------------------------------------------}
  765.  
  766. FUNCTION  Db3_field2str(no :INTEGER) : STRING;
  767.  
  768. VAR
  769.   s : STRING;
  770.   i : WORD;
  771.  
  772. BEGIN
  773.   s:='';
  774.   IF (no IN [1..nofields])
  775.     THEN
  776.       BEGIN
  777.         s[0]:=Chr(fieldptr[no].fplen);
  778.         Move(dbrec^[fieldptr[no].fppos],s[1],fieldptr[no].fplen);
  779.       END
  780.     ELSE Seternr(16);
  781. {----Strip Trailing Spaces}
  782.   WHILE (Length(s)>0) AND (s[Length(s)]=#32) DO Dec(s[0]);
  783.   Db3_field2str:=s;
  784. END; {of Db3_field2str}
  785.  
  786. {---------------------------------------------------------}
  787.  
  788. FUNCTION Db3_field2char(no :INTEGER) : CHAR;
  789.  
  790. VAR
  791.   s : STRING;
  792.  
  793. BEGIN
  794.   IF (Db3_fieldlen(no)=1)
  795.     THEN s:=Db3_field2str(no)
  796.     ELSE s:=#00;
  797.  
  798.   IF (Length(s)=0)
  799.     THEN Db3_field2char:=#32
  800.     ELSE Db3_field2char:=s[1];
  801. END; {of Db3_field2char}
  802.  
  803. {---------------------------------------------------------}
  804.  
  805. FUNCTION Db3_field2logic(no : INTEGER) : BOOLEAN;
  806.  
  807. BEGIN
  808.   Db3_field2logic:=(Db3_field2char(no)='T');
  809. END; {of Db3_field2logic}
  810.  
  811. {---------------------------------------------------------}
  812.  
  813. FUNCTION  Db3_field2num(no : INTEGER) : REAL;
  814.  
  815. VAR
  816.   r : REAL;
  817.   s : STRING;
  818.   e : INTEGER;
  819.  
  820. BEGIN
  821.   s:=Db3_field2str(no);
  822.   WHILE (Length(s)>0) AND (s[1]=#32) DO Delete(s,1,1);
  823.   Val(s,r,e);
  824.   IF (e<>0)
  825.     THEN Seternr(5);
  826.   Db3_field2num:=r;
  827. END; {of Db3_field2num}
  828.  
  829. {---------------------------------------------------------}
  830.  
  831. FUNCTION  Db3_field2date(no :INTEGER) : STRING;
  832.  
  833. VAR
  834.   s : STRING;
  835.  
  836. BEGIN
  837.   s:='dd-mm-yyyy';
  838.   IF (no IN [1..nofields])
  839.     THEN
  840.       BEGIN
  841.         Move(dbrec^[fieldptr[no].fppos+6],s[1],2);
  842.         Move(dbrec^[fieldptr[no].fppos+4],s[4],2);
  843.         Move(dbrec^[fieldptr[no].fppos+0],s[7],4);
  844.       END
  845.     ELSE Seternr(16);
  846.  
  847.   Db3_field2date:=s;
  848. END; {of Db3_field2date}
  849.  
  850. {---------------------------------------------------------}
  851.  
  852. FUNCTION Db3_field2soundex(no : INTEGER) : STRING;
  853.  
  854. BEGIN
  855.   Db3_field2soundex:=Db3_soundex(Db3_field2str(no));
  856. END; {of Db3_field2soundex}
  857.  
  858. {---------------------------------------------------------}
  859.  
  860. PROCEDURE Db3_str2field(no :INTEGER;s : STRING);
  861.  
  862. BEGIN
  863.   IF (no IN [1..nofields])
  864.     THEN
  865.       BEGIN
  866.         Fillchar(dbrec^[fieldptr[no].fppos],fieldptr[no].fplen,#32);
  867.         WITH fields[no] DO
  868.           IF (Length(s)>dblen)
  869.             THEN Move(s[1],dbrec^[fieldptr[no].fppos],dblen)
  870.             ELSE Move(s[1],dbrec^[fieldptr[no].fppos],Length(s));
  871.       END
  872.     ELSE Seternr(16)
  873. END; {of Db3_str2field}
  874.  
  875. {---------------------------------------------------------}
  876.  
  877. PROCEDURE Db3_char2field(no :INTEGER;s : CHAR);
  878.  
  879. BEGIN
  880.   Db3_str2field(no,s);
  881. END; {of Db3_char2field}
  882.  
  883. {---------------------------------------------------------}
  884.  
  885. PROCEDURE Db3_logic2field(no : INTEGER;l : BOOLEAN);
  886.  
  887. BEGIN
  888.   IF l
  889.     THEN Db3_char2field(no,'T')
  890.     ELSE Db3_char2field(no,'F')
  891. END; {of Db3_logic2field}
  892.  
  893. {---------------------------------------------------------}
  894.  
  895. PROCEDURE Db3_num2field(no : INTEGER;n: REAL);
  896.  
  897. VAR
  898.   s : STRING;
  899.  
  900. BEGIN
  901.   IF (no IN [1..nofields])
  902.     THEN
  903.       BEGIN
  904.         Str(n:fields[no].dblen:fields[no].dbdec,s);
  905.         IF (Length(s)>fields[no].dblen)
  906.           THEN Seternr(12)
  907.           ELSE Db3_str2field(no,s);
  908.       END
  909.     ELSE Seternr(16)
  910. END; {of Db3_num2field}
  911.  
  912. {---------------------------------------------------------}
  913.  
  914. PROCEDURE Db3_date2field(no :INTEGER;d : STRING);
  915.  
  916. VAR
  917.   s : STRING;
  918.  
  919. BEGIN
  920.   IF (Length(d)<>10) OR
  921.      (d[3]<>'-') OR
  922.      (d[6]<>'-')
  923.     THEN Seternr(11)
  924.     ELSE
  925.       BEGIN
  926.       {----dd-mm-yyyy}
  927.         s[1]:=d[ 7];
  928.         s[2]:=d[ 8];
  929.         s[3]:=d[ 9];
  930.         s[4]:=d[10];
  931.         s[5]:=d[ 4];
  932.         s[6]:=d[ 5];
  933.         s[7]:=d[ 1];
  934.         s[8]:=d[ 2];
  935.         Db3_str2field(no,s);
  936.       END;
  937. END; {of Db3_date2field}
  938.  
  939. {---------------------------------------------------------}
  940. {----Memo text field support                              }
  941. {---------------------------------------------------------}
  942.  
  943. {$F+}
  944.  
  945. FUNCTION memoignore(VAR f : textrec) : INTEGER;
  946.  
  947. BEGIN
  948.   memoignore:=0;
  949. END; {of memoignore}
  950.  
  951. {---------------------------------------------------------}
  952.  
  953. FUNCTION memoinput(VAR f : textrec) : INTEGER;
  954.  
  955. VAR
  956.   chread : WORD;
  957.  
  958. BEGIN
  959.   WITH Textrec(f) DO
  960.     BEGIN
  961.       Blockread(memo,memobuf[1],Sizeof(memobuf),chread);
  962.       bufpos   :=0;
  963.       bufend   :=chread;
  964.     END;
  965.   memoinput:=0;
  966. END; {of memoinput}
  967.  
  968. {$F-}
  969.  
  970. {---------------------------------------------------------}
  971.  
  972. PROCEDURE Assignmemo(VAR f : TEXT);
  973.  
  974. VAR
  975.   chread : WORD;
  976.  
  977. CONST
  978.   fminput =$D7B1;
  979.  
  980. BEGIN
  981.   WITH Textrec(f) DO
  982.     BEGIN
  983.       handle   :=$ffff;
  984.       mode     :=fminput;
  985.       bufsize  :=SIZEOF(memobuf);
  986.       bufpos   :=0;
  987.       bufptr   :=@memobuf;
  988.  
  989.       Blockread(memo,memobuf[1],Sizeof(memobuf),chread);
  990.       bufpos   :=0;
  991.       bufend   :=chread;
  992.  
  993.       openfunc :=@memoignore;
  994.       inoutfunc:=@memoinput;
  995.       flushfunc:=@memoignore;
  996.       closefunc:=@memoignore;
  997.       name[0]  :=#00;
  998.     END;
  999. END; {of Assignmemo}
  1000.  
  1001. {---------------------------------------------------------}
  1002.  
  1003. PROCEDURE Db3_field2memo(no : INTEGER);
  1004.  
  1005. VAR
  1006.   e  : INTEGER;
  1007.   s  : STRING;
  1008.  
  1009. BEGIN
  1010.   IF Db3_memo
  1011.     THEN
  1012.       BEGIN
  1013.         s:=Db3_field2str(no);
  1014.         WHILE (Length(s)>0) AND (s[1]=#32) DO Delete(s,1,1);
  1015.         Val(s,memopos,e);
  1016.         IF (e<>0)
  1017.           THEN Seternr(5)
  1018.           ELSE
  1019.             BEGIN
  1020.               Seek(memo,memopos*Sizeof(memobuf));
  1021.               Assignmemo(db3_memotext);
  1022.             END;
  1023.       END
  1024.     ELSE Seternr(17);
  1025. END; {of Db3_field2memo}
  1026.  
  1027. {---------------------------------------------------------}
  1028.  
  1029. FUNCTION Db3_findfirst(cs : BOOLEAN) : BOOLEAN;
  1030.  
  1031. VAR
  1032.   match,
  1033.   found : BOOLEAN;
  1034.   i     : INTEGER;
  1035.  
  1036. BEGIN
  1037.   Getmem(dbsearch,Db3_reclen+1);
  1038.   Move(dbrec^,dbsearch^,Db3_reclen);
  1039.  
  1040.   Db3_Seekbof;
  1041.  
  1042.   found:=False;
  1043.   WHILE NOT(found OR Db3_eof OR (Db3_ernr<>0)) DO
  1044.     BEGIN
  1045.       Db3_readnext;
  1046.  
  1047.       i:=0;
  1048.       match:=true;
  1049.       WHILE (i<Db3_reclen) AND match DO
  1050.         BEGIN
  1051.           IF (dbsearch^[i]<>#32)
  1052.             THEN
  1053.               CASE cs OF
  1054.                 TRUE  : match:=(       dbsearch^[i] =       dbrec^[i]);
  1055.                 FALSE : match:=(Upcase(dbsearch^[i])=Upcase(dbrec^[i]));
  1056.               END;
  1057.           INC(i);
  1058.         END;
  1059.       found:=match;
  1060.     END;
  1061.  
  1062.   Db3_findfirst:=found;
  1063.  
  1064.   IF (found=False)
  1065.     THEN
  1066.       BEGIN
  1067.         Freemem(dbsearch,Db3_reclen+1);
  1068.         dbsearch:=NIL;
  1069.       END;
  1070. END; {of Db3_findfirst}
  1071.  
  1072. {---------------------------------------------------------}
  1073.  
  1074. FUNCTION Db3_findnext(cs : BOOLEAN) : BOOLEAN;
  1075.  
  1076. VAR
  1077.   match,
  1078.   found : BOOLEAN;
  1079.   i     : INTEGER;
  1080.  
  1081. BEGIN
  1082.   IF (dbsearch=NIL)
  1083.     THEN Seternr(18);
  1084.  
  1085.   found:=False;
  1086.   WHILE NOT(found OR Db3_eof OR (Db3_ernr<>0)) DO
  1087.     BEGIN
  1088.       Db3_readnext;
  1089.  
  1090.       i:=0;
  1091.       match:=true;
  1092.       WHILE (i<Db3_reclen) AND match DO
  1093.         BEGIN
  1094.           IF (dbsearch^[i]<>#32)
  1095.             THEN
  1096.               CASE cs OF
  1097.                 TRUE  : match:=(       dbsearch^[i] =       dbrec^[i]);
  1098.                 FALSE : match:=(Upcase(dbsearch^[i])=Upcase(dbrec^[i]));
  1099.               END;
  1100.           INC(i);
  1101.         END;
  1102.       found:=match;
  1103.     END;
  1104.  
  1105.   Db3_findnext:=found;
  1106.  
  1107.   If (found=False) AND (dbsearch<>NIL)
  1108.     Then
  1109.       BEGIN
  1110.         Freemem(dbsearch,Db3_reclen+1);
  1111.         dbsearch:=NIL;
  1112.       END;
  1113. END; {of Db3_findnext}
  1114.  
  1115. {---------------------------------------------------------}
  1116.  
  1117. FUNCTION  Db3_soundex(name : STRING) : STRING;
  1118.  
  1119. VAR
  1120.   work : STRING;
  1121.   code : CHAR;
  1122.   i,j  : INTEGER;
  1123.  
  1124.   {---------------------------------------------------------}
  1125.  
  1126.   FUNCTION Encode(VAR c: CHAR): CHAR;
  1127.  
  1128.   BEGIN
  1129.     CASE Upcase(c) OF
  1130.       'B','F','P','V':                 encode:='1';
  1131.       'C','G','J','K','Q','S','X','Z': encode:='2';
  1132.       'D','T':                         encode:='3';
  1133.       'L':                             encode:='4';
  1134.       'M','N':                         encode:='5';
  1135.       'R':                             encode:='6';
  1136.       'A','E','I','O','U','Y':         encode:='7';
  1137.       'H','W':                         encode:='8';
  1138.     ELSE                               encode:=' ';
  1139.     END;
  1140.   END; {of Encode}
  1141.  
  1142.   {---------------------------------------------------------}
  1143.  
  1144. BEGIN
  1145. {----If we can't calculate, this is the answer}
  1146.   work:='';
  1147.  
  1148. {----Skip all non alpha codes in front}
  1149.   i:=1;
  1150.   WHILE (i<=Length(name)) AND (Encode(name[i])=' ') DO Inc(i);
  1151.  
  1152. {----If any alpha characters left, start calculating the SOUNDEX code}
  1153.   IF (i<=Length(name))
  1154.     THEN
  1155.       BEGIN
  1156.       {----The first alpha letter of string is the first letter of the code}
  1157.         work:=Upcase(name[i]);
  1158.         Inc(i);
  1159.  
  1160.       {----Be sure while loop precondition is correct}
  1161.         j:=1;
  1162.         code:=#00;
  1163.  
  1164.       {----Calculate the numeric part of the code,    }
  1165.       {    with a maximum of 3 digits, stop if a non  }
  1166.       {    alpha character is encountered             }
  1167.         WHILE (i<=Length(name)) AND (j<=3) AND (code<>' ') DO
  1168.           BEGIN
  1169.             code:=Encode(name[i]);
  1170.  
  1171.           {----If new code group then add the goup number}
  1172.             IF (code IN ['1'..'6']) AND (work[j]<>code)
  1173.               THEN
  1174.                 BEGIN
  1175.                   Inc(j);
  1176.                   work:=work+code;
  1177.                 END;
  1178.             Inc(i);
  1179.           END;
  1180.       END;
  1181.  
  1182. {----Return the resulting SOUNDEX code}
  1183.   Db3_soundex:=work;
  1184.  
  1185. END; {of Db3_soundex}
  1186.  
  1187. {---------------------------------------------------------}
  1188.  
  1189. FUNCTION Db3_firstsoundex(no : INTEGER;s : STRING) : BOOLEAN;
  1190.  
  1191. VAR
  1192.   found : BOOLEAN;
  1193.   sdx   : STRING;
  1194.  
  1195. BEGIN
  1196.   Db3_Seekbof;
  1197.  
  1198.   sdx:=Db3_soundex(s);
  1199.  
  1200.   found:=False;
  1201.   WHILE NOT(found OR Db3_eof OR (Db3_ernr<>0)) DO
  1202.     BEGIN
  1203.       Db3_readnext;
  1204.       found:=(Pos(sdx,Db3_field2soundex(no))=1);
  1205.     END;
  1206.  
  1207.   Db3_firstsoundex:=found;
  1208. END; {of Db3_firstsoundex}
  1209.  
  1210. {---------------------------------------------------------}
  1211.  
  1212. FUNCTION Db3_nextsoundex(no : INTEGER; s : STRING) : BOOLEAN;
  1213.  
  1214. VAR
  1215.   found : BOOLEAN;
  1216.   sdx   : STRING;
  1217.  
  1218. BEGIN
  1219.   sdx:=Db3_soundex(s);
  1220.  
  1221.   found:=False;
  1222.   WHILE NOT(found OR Db3_eof OR (Db3_ernr<>0)) DO
  1223.     BEGIN
  1224.       Db3_readnext;
  1225.       found:=(Pos(sdx,Db3_field2soundex(no))=1);
  1226.     END;
  1227.  
  1228.   Db3_nextsoundex:=found;
  1229. END; {of Db3_nextsoundex}
  1230.  
  1231. {---------------------------------------------------------}
  1232.  
  1233. PROCEDURE Db3_sort(no : INTEGER);
  1234.  
  1235. VAR
  1236.   dbsort    : ^rectyp;
  1237.   swapped   : BOOLEAN;
  1238.   i,j,l,r   : LONGINT;
  1239.   s1,s2     : STRING;
  1240.   typ       : CHAR;
  1241.  
  1242.   {---------------------------------------------------------}
  1243.  
  1244.   PROCEDURE Swap(r1,r2 : LONGINT);
  1245.  
  1246.   BEGIN
  1247.   {----Side Effects}
  1248.     i:=j;
  1249.     swapped:=True;
  1250.  
  1251.   {----the Swapping itself}
  1252.     Db3_replace(r1);
  1253.     Move(dbsort^,dbrec^,Db3_reclen);
  1254.     Db3_replace(r2);
  1255.   END; {of Swapped}
  1256.  
  1257.   {---------------------------------------------------------}
  1258.  
  1259.   FUNCTION Compare(VAR c1,c2 : STRING) : BOOLEAN;
  1260.  
  1261.   VAR
  1262.     i : INTEGER;
  1263.     s : STRING;
  1264.  
  1265.   BEGIN
  1266.     CASE typ OF
  1267.       'M',
  1268.       'N'  : BEGIN
  1269.              {----Insert spaces for correct numeric compare}
  1270.                FOR i:=1 TO Db3_fieldlen(no)-Length(c1) DO Insert(#32,c1,i);
  1271.                FOR i:=1 TO Db3_fieldlen(no)-Length(c2) DO Insert(#32,c2,i);
  1272.              END;
  1273.       'L',
  1274.       'S',
  1275.       'C'  : BEGIN
  1276.              {----Convert to Uppercase for correct alpha compare}
  1277.                FOR i:=1 TO Length(c1) Do c1[i]:=Upcase(c1[i]);
  1278.                FOR i:=1 TO Length(c2) Do c2[i]:=Upcase(c2[i]);
  1279.              END;
  1280.       'D'  : ;
  1281.     END;
  1282.  
  1283.   {----Return TRUE if c2>c1}
  1284.     Compare:=(c2>c1);
  1285.   END; {of Compare}
  1286.  
  1287.   {---------------------------------------------------------}
  1288.  
  1289. BEGIN
  1290. {----Use ShakerSort on almost sorted *.DBF file}
  1291.   Getmem(dbsort,Db3_reclen+1);
  1292.   Move(dbrec^,dbsort^,Db3_reclen);
  1293.  
  1294.   l:=2;
  1295.   r:=Db3_filesize;
  1296.   i:=r-1;
  1297.  
  1298.   swapped:=TRUE;
  1299.   typ    :=Db3_fieldtype(no);
  1300.  
  1301.   WHILE (l<=r) AND swapped DO
  1302.     BEGIN
  1303.       swapped:=False;
  1304.  
  1305.     {----Bubble Up}
  1306.       FOR j:=r DOWNTO l DO
  1307.         BEGIN
  1308.         {----Fetch record j-1 & save it}
  1309.           Db3_read(j-1);
  1310.           s2:=Db3_field2str(no);
  1311.           Move(dbrec^,dbsort^,Db3_reclen);
  1312.  
  1313.         {----Fetch record j}
  1314.           Db3_read(j);
  1315.           s1:=Db3_field2str(no);
  1316.  
  1317.         {----Bubble}
  1318.           IF Compare(s1,s2)
  1319.             THEN Swap(j-1,j);
  1320.         END;
  1321.       l:=i+1;
  1322.  
  1323.     {----Bubble Down}
  1324.       IF swapped
  1325.         THEN
  1326.           BEGIN
  1327.             FOR j:=l TO r DO
  1328.               BEGIN
  1329.               {----Fetch record j-1 & save it}
  1330.                 Db3_read(j-1);
  1331.                 s2:=Db3_field2str(no);
  1332.                 Move(dbrec^,dbsort^,Db3_reclen);
  1333.  
  1334.               {----Fetch record j}
  1335.                 Db3_read(j);
  1336.                 s1:=Db3_field2str(no);
  1337.  
  1338.               {----Bubble}
  1339.                 IF Compare(s1,s2)
  1340.                   THEN Swap(j-1,j);
  1341.               END;
  1342.             r:=i-1;
  1343.           END;
  1344.     END;
  1345.  
  1346.   Freemem(dbsort,Db3_reclen+1);
  1347.  
  1348.   Db3_seekbof;
  1349. END; {of Db3_sort}
  1350.  
  1351. {---------------------------------------------------------}
  1352.  
  1353. BEGIN
  1354.   db3_ernr :=0;
  1355.   db3_fatal:=False;
  1356.   dbsearch :=NIL;
  1357.   dbrec    :=NIL;
  1358. END.
  1359.  
  1360.  
  1361. { DOCUMENTATION }
  1362.  
  1363. Db3_01.PAS is written by
  1364.  
  1365.                 Ir. G.W. van der Vegt
  1366.                 Hondbroek 57
  1367.                 6121 XB Born (L)
  1368.  
  1369. and uploaded as public domain software because the author likes to
  1370. share it with other Turbo Pascal Users. Please keep the source the
  1371. way it is and write extentions as separate units.
  1372.  
  1373. This unit provides read/write access to Dbase III (Plus) *.DBF files. The
  1374. unit is uploaded as it is, the author is not responsible for any damgage
  1375. by programs using this module. The unit is, of course, tested.
  1376.  
  1377. Before using any of the Db3 routine a program shall call Db3_open to
  1378. initialize the file internal buffers & info. When finishing the program
  1379. should call Db3_close to close the file & cleanup the internal buffer.
  1380.  
  1381. All routines are documented so there's not much to say about them. Access
  1382. to the DBF file is only allowed through this unit, so the file record
  1383. isn't exported.
  1384.  
  1385. Records must be read by Db3_read or Db3_readnext, and written by Db3_append
  1386. or Db3_replace. All record functions use LONGINTs as parameter for addressing
  1387. records in the file.
  1388.  
  1389. When a record is read, one can read the field in the record by using the
  1390. record number as parameter of the Db3_field2 procedures. This record
  1391. number lies between 1 and maxfield. If one 's to be independend of the
  1392. location of the record the Db3_fieldno can be used to convert a field
  1393. name to the field number.
  1394.  
  1395. When writing records fill all field with Db3_2field routines and don't
  1396. forget to use Db3_undelete to initialize the deleted marker. It's of
  1397. course also possible to read a record, modify some field and replace it.
  1398.  
  1399. The Db3_pack routine packs the file in-place, so no temp file is created.
  1400.  
  1401. This unit can't create DBase III *.DBF files as it can't write the file
  1402. header & fieldefinitions. It's also impossble to change the structure of
  1403. a DBase III *.DBF database with it. This is done to keep the unit simple.
  1404. Creating & modifing databases is much easier in Dbase III Language.
  1405.  
  1406. This unit uses a special naming convention to be sure there's no
  1407. confict with procedures from other units. All exported names have
  1408. a three letter prefix Db3_. The 01 in the Unit name is a unique
  1409. version number.
  1410.